package com.free.bsf.core.serialize;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.free.bsf.core.base.BsfException;
import com.free.bsf.core.config.CoreProperties;
import com.free.bsf.core.util.PropertyUtils;
import lombok.Getter;
import lombok.Setter;
import lombok.val;

import java.lang.reflect.Type;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.TimeZone;

/**
 * @author Huang Zhaoping
 */
public class JsonSerializer implements Serializer {

    public static JavaTimeModule getJavaTimeModule(String dateFormat,String dateTimeFormat){
        JavaTimeModule timeModule = new JavaTimeModule();
        timeModule.addDeserializer(Date.class, new TimeDeSerializer.DateDeserializer(dateTimeFormat));
        timeModule.addDeserializer(LocalDate.class, new TimeDeSerializer.LocalDateDeserializer(dateFormat));
        timeModule.addDeserializer(LocalDateTime.class, new TimeDeSerializer.LocalDateTimeDeserializer(dateTimeFormat));
        timeModule.addSerializer(LocalDate.class,
                new LocalDateSerializer(DateTimeFormatter.ofPattern(dateFormat)));
        timeModule.addSerializer(LocalDateTime.class,
                new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(dateTimeFormat)));
        return timeModule;
    }

    public static ObjectMapper createDefaultMapper(){
        val obj = createObjectMapper();
        if(PropertyUtils.getPropertyCache(CoreProperties.BsfJsonDateTime,true)){
            obj.registerModule(getJavaTimeModule(PropertyUtils.getPropertyCache(CoreProperties.BsfJsonDateFormat,"yyyy-MM-dd"),PropertyUtils.getPropertyCache(CoreProperties.SpringJacksonDateFormat,"yyyy-MM-dd HH:mm:ss")));
        }
        if(PropertyUtils.getPropertyCache(CoreProperties.BsfJsonJDK8,true)){
            obj.registerModule(new Jdk8Module());
        }
        return obj;
    }

    public static ObjectMapper createObjectMapper(){
       val obj =  new ObjectMapper()
                .enable(MapperFeature.USE_ANNOTATIONS)
                .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)
                .disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
                .configure(MapperFeature.ACCEPT_CASE_INSENSITIVE_PROPERTIES,PropertyUtils.getPropertyCache(CoreProperties.BsfJsonIgnoreCaseEnabled,true))
               //允许不带引号的字段
               .configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true)
               //允许单引号
                .configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true)
                .setTimeZone(TimeZone.getTimeZone(PropertyUtils.getPropertyCache(CoreProperties.SpringJacksonTimeZone,"GMT+8")))
                .setDateFormat(new SimpleDateFormat(PropertyUtils.getPropertyCache(CoreProperties.SpringJacksonDateFormat,"yyyy-MM-dd HH:mm:ss")));
       if(PropertyUtils.getPropertyCache(CoreProperties.BsfJsonIncludeNotNull,true)){
            obj.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            //obj.configure(SerializationFeature.WRITE_NULL_MAP_VALUES, false);
       }
       return obj;
    }

    private static ObjectMapper defaultObjectMapper = createDefaultMapper();

    public static ObjectMapper getDefaultObjectMapper() {
        return defaultObjectMapper;
    }

    @Getter @Setter
    private ObjectMapper objectMapper;
    private ObjectMapper getMapper(){
        if(objectMapper==null){
            return defaultObjectMapper;
        }
        return objectMapper;
    }

    @Override
    public String serialize(Object object) {
        try {
            return getMapper().writeValueAsString(object);
        } catch (Exception e) {
            throw new BsfException("序列化失败，对象：" + object, e);
        }
    }

    @Override
    public <T> T deserialize(String str, Type type) {
        try {
            return getMapper().readValue(str, new TypeReference<Object>(){
                @Override
                public Type getType() {
                    return type;
                }
            });
        } catch (Exception e) {
            throw new BsfException("反序列化失败，类型：" + type + "，JSON：" + str, e);
        }
    }

}
